//! 监听地址变化设置阻塞(核心发布订阅模式)

export class Manager {
    // 存放监听器
    listeners = [];
    // 存储阻塞有值表示设置了阻塞没有则没设置
    prompt = null;
    // 阻塞方法
    constructor(getUserConfirmation) {
        this.getUserConfirmation = getUserConfirmation;
    }
    /**
     * 添加监听器，返回取消监听函数
     * @param {*} listener 监听器
     * @returns 取消监听器
     */
    appendListener(listener) {
        let isActive = true;
        isActive && this.listeners.push(listener);
        // 返回得到取消监听函数
        return () => {
            isActive = false;
            this.listeners.splice(this.listeners.indexOf(listener), 1);
        };
    }
    /**
     * 触发发布所有监听器
     * @param {*} location location
     * @param {*} action  触发的行为
     */
    tiggerListener(location, action) {
        for (const listener of this.listeners) {
            listener(location, action);
        }
    }
    /**
     * 设置阻塞消息
     * @param {*} nextPrompt  可以是字符串也可以是函数(但该函数返回一个信息字符串)
     * @returns 取消阻塞
     */
    setPrompt(nextPrompt) {
        // 传递参数只能是字符串和函数
        const whitelist = ["string", "function"];
        if (!whitelist.includes(typeof prompt)) {
            throw new TypeError("block must be string or function"); // 不满足条件类型直接抛错错误
        }
        this.prompt = nextPrompt;
        // 返回取消阻塞
        return () => {
            this.prompt === nextPrompt && (this.prompt = null);
        };
    }
    /**
     * 触发阻塞
     * @param {*} location 
     * @param {*} action 
     * @param {*} callback 控制是否进行阻塞跳转
     */
    triggerPrompt(location, action, callback) {
        if (prompt != null) {
            // 阻塞消息(阻塞时字符串直接赋值，如果时函数则传入参数执行获取返回值得到阻塞消息)
            const message = typeof this.prompt === 'function' ? this.prompt(location, action) : this.prompt;
            if (typeof message === 'string') {
                if (typeof this.getUserConfirmation === 'function') {
                    // 调用触发执行 getUserConfirmation (参数需要阻塞消息,以及用户回调函数接收一个布尔值)
                    this.getUserConfirmation(message, (result) => {
                        callback(result) // 回调函数为真实执行阻塞后回调
                    });
                } else {
                    callback(true);
                }
            } else {
                callback(message !== false);
            }
        } else {
            callback(true); // 没有阻塞直接执行回调事件
        }
    }
}